<template>
  <div class="program-transfer">
    <unfold :isShowInnerLoading="isShowInnerLoading" isShowInnerCard>
      <!-- 左侧角色列表 -->
      <template v-slot:tree-list>
        <tree-list
          ref="treeList"
          head-name="程序传输"
          head-icon="iconfont icontubiao-159"
          :list="treeList"
          @setAct="setAct"
          :show-refresh="false"
          :show-fold="false"
          :isDisable="isShowInnerLoading"
        ></tree-list>
      </template>

      <!-- 右侧 card -->
      <template v-slot:content>
        <div
          class="full-height relative-position page-content"
          style="padding: 0"
        >
          <!--  头部-->
          <div class="file-head row no-wrap bg-primary text-white form-inline">
            <q-btn-dropdown
              v-show="positionType === 'machine'"
              label="本地发送"
              :disable="actFile.length === 0 || isShowDui"
              unelevated
              color="white"
              text-color="primary"
              class="margin-r-10 btn-dropdown"
            >
              <q-list dense>
                <q-item clickable v-close-popup class="no-padding">
                  <q-item-section>
                    <!--                  <q-item-label>内部存储</q-item-label>-->
                    <q-btn
                      label="内部存储"
                      flat
                      @click.stop="
                        testMachineNum;
                        $refs.uploadInputCnc.click();
                      "
                    >
                      <input
                        ref="uploadInputCnc"
                        type="file"
                        @change="uploadManyLocalFile($event, 'cnc')"
                        multiple
                        v-show="false"
                        class="q-uploader__input overflow-hidden absolute-full"
                      />
                    </q-btn>
                  </q-item-section>
                </q-item>
                <q-item clickable v-close-popup class="no-padding">
                  <q-item-section>
                    <!--                  <q-item-label>外部存储</q-item-label>-->
                    <q-btn
                      label="外部存储"
                      flat
                      @click.stop="
                        testMachineNum;
                        $refs.uploadInputBox.click();
                      "
                    >
                      <input
                        ref="uploadInputBox"
                        type="file"
                        @change="uploadManyLocalFile($event, 'box')"
                        multiple
                        v-show="false"
                        class="q-uploader__input overflow-hidden absolute-full"
                      />
                    </q-btn>
                  </q-item-section>
                </q-item>
              </q-list>
            </q-btn-dropdown>
            <q-btn-dropdown
              v-show="positionType === 'machine'"
              label="远程发送"
              :disable="actFile.length === 0"
              unelevated
              color="white"
              text-color="primary"
            >
              <q-list dense>
                <q-item
                  clickable
                  v-close-popup
                  @click="showCloudFileDialog($event, 'cnc')"
                >
                  <q-item-section>
                    <q-item-label>内部存储</q-item-label>
                  </q-item-section>
                </q-item>
                <q-item
                  clickable
                  v-close-popup
                  @click="showCloudFileDialog($event, 'box')"
                >
                  <q-item-section>
                    <q-item-label>外部存储</q-item-label>
                  </q-item-section>
                </q-item>
              </q-list>
            </q-btn-dropdown>

            <q-btn
              v-show="positionType === 'file'"
              label="本地发送"
              :disable="isShowDui"
              @click.stop="$refs.uploadInputFile.click()"
              unelevated
              color="white"
              text-color="primary"
              class="margin-r-10"
            >
              <input
                ref="uploadInputFile"
                type="file"
                @change="uploadLocalFile($event)"
                multiple
                v-show="false"
                class="q-uploader__input overflow-hidden absolute-full"
              />
            </q-btn>
            <q-btn
              v-show="positionType === 'file'"
              label="远程发送"
              @click="showCloudFileDialog"
              unelevated
              color="white"
              text-color="primary"
              class="margin-r-10"
            />
            <q-btn
              v-show="positionType === 'file'"
              label="保存到远程"
              @click="showCloudSelDir"
              :disable="actFile.length === 0"
              unelevated
              color="white"
              text-color="primary"
              class="margin-r-10"
            />
            <q-btn
              v-show="positionType === 'file'"
              label="下载到本地"
              :disable="actFile.length === 0"
              unelevated
              color="white"
              text-color="primary"
            >
              <input
                ref="uploadInput"
                @click="showLocalDirDialog"
                multiple
                v-show="actFile.length > 0"
                class="q-uploader__input overflow-hidden absolute-full"
              />
            </q-btn>
            <span
              style="margin-left: 10px;cursor: pointer"
              @click="dialogVisible = true"
              >格式说明</span
            >

            <q-space></q-space>

            <select-input
              ref="selectInput"
              v-if="positionType === 'machine'"
              :list="searchCondition"
              @search="inputSearch"
              @clearSearchVal="clearSearchVal"
            />
            <q-icon
              v-show="positionType !== 'machine'"
              name="iconfont icontubiao-58"
              class="icon"
              @click="back()"
            >
              <q-tooltip>返回上一级</q-tooltip>
            </q-icon>
            <q-icon
              @click="changeLookStatus"
              v-show="positionType === 'file'"
              :name="
                positionType === 'list'
                  ? 'iconfont icontubiao-104'
                  : 'iconfont icontubiao-57'
              "
              class="icon"
            >
              <q-tooltip>切换显示模式</q-tooltip>
            </q-icon>
            <q-icon
              name="iconfont icontubiao-34"
              class="icon"
              @click="refreshFun"
            >
              <q-tooltip>刷新</q-tooltip>
            </q-icon>
          </div>
          <!--  路径-->
          <position :position="position" :total="files.length" @goto="goto" />
          <!--  内容-->
          <div
            class="list-content drop-target relative-position"
            @mousedown="boxStart($event, 'fileList')"
            ref="fileList"
          >
            <div
              class="full-height"
              v-if="lookStatus === 'bigIcon'"
              @click.self="clearActFile()"
            >
              <q-scroll-area
                :thumb-style="CommonConfig.thumbStyle"
                class="full-height"
              >
                <div class="full-height list" v-if="positionType !== 'file'">
                  <file-item
                    v-for="(file, fileIndex) in files"
                    :key="fileIndex"
                    :is-show-menu="false"
                    :file="file"
                    :file-index="fileIndex"
                    class="machine-file"
                    :is-active="isActDay(file)"
                    @selFiles="selFiles"
                    @dblclickE="dblclickE"
                  />
                </div>
                <div class="full-height list" v-else>
                  <file-item
                    v-for="(file, fileIndex) in files"
                    :key="fileIndex"
                    :ref="'fileItem' + file.id"
                    :file="file"
                    :file-index="fileIndex"
                    :is-active="isActDay(file)"
                    @selFiles="selFiles"
                    @dblclickE="dblclickE"
                    @setFile="setFile"
                    @setNewNameFun="setNewNameFun"
                    @deleteFun="deleteFun"
                    @editFile="editFile"
                  />
                </div>
              </q-scroll-area>
              <q-menu
                touch-position
                context-menu
                v-if="positionType === 'file'"
              >
                <q-list dense style="min-width: 150px">
                  <q-item clickable v-close-popup @click="newFolder">
                    <q-item-section>新建文件夹</q-item-section>
                  </q-item>
                  <q-item clickable v-close-popup @click="newFile">
                    <q-item-section>新建文件</q-item-section>
                  </q-item>
                </q-list>
              </q-menu>
            </div>
            <div
              class="full-height"
              v-if="positionType === 'file' && lookStatus !== 'bigIcon'"
              @click.self="clearActFile"
            >
              <q-table
                class="table-file"
                :pagination="pagination"
                no-data-label="暂无数据"
                :data="files"
                :columns="columns"
                row-key="id"
                hide-bottom
                binary-state-sort
                @request="onRequest"
              >
                <template v-slot:body="props">
                  <file-item-tr
                    :file="props"
                    :is-active="isActDay(props.row)"
                    :ref="'fileItemTr' + props.row.id"
                    @selFiles="selFiles"
                    @dblclickE="dblclickE"
                    @setFile="setFile"
                    @setNewNameFun="setNewNameFun"
                    @deleteFun="deleteFun"
                    :isShowAdd="false"
                    @editFile="editFile"
                  />
                </template>
              </q-table>
              <q-menu touch-position context-menu>
                <q-list dense style="min-width: 150px">
                  <q-item clickable v-close-popup @click="newFolder">
                    <q-item-section>新建文件夹</q-item-section>
                  </q-item>
                  <q-item clickable v-close-popup @click="newFile">
                    <q-item-section>新建文件</q-item-section>
                  </q-item>
                </q-list>
              </q-menu>
            </div>
            <div class="box-select" ref="boxSelect"></div>
            <q-inner-loading :showing="loading">
              <q-spinner-gears size="50px" color="primary" />
            </q-inner-loading>
          </div>
          <!--        底部-->
          <div class="file-bottom">
            <q-btn
              label="操作记录"
              color="primary"
              @click="showProgressResult"
              outline
              size="small"
            />
            <div
              class="progressResult text-primary text-underline cursor-pointer"
              @click="showProgressResult"
            >
              <!--            传输记录：正在传输({{progressFiles.length}})； 传输成功({{successProgressFiles.length}})； 传输失败({{failProgressFiles.length}})-->
            </div>
          </div>
        </div>
      </template>
    </unfold>
    <!--  右下角正在上传的弹框-->
    <progress-dialog ref="progressDialog" :list="progressFiles" />
    <!--  文件传输记录-->
    <progress-result-dialog
      ref="progressResult"
      :doing-data="doingProgressFiles"
      :success-data="successProgressFiles"
      :fail-data="failProgressFiles"
      @delOneRecord="delOneRecord"
      @clearRecord="clearRecord"
    />
    <!--  文件内容编辑插件-->
    <code-edit
      ref="codeEdit"
      :value="editFileContent"
      :name="editFileName"
      :decode="edtiFileDecode"
      :path="editFilePath"
      :state="codeState"
      @refreshList="refreshFun"
      @save="saveFile"
    ></code-edit>
    <cloud-file-dialog ref="cloudFileDialog" @submit="uploadCloudFile" />
    <cloud-sel-dir ref="cloudSelDir" @submit="uploadMachineToCloud" />

    <Drawer
      :header-show="false"
      :visible.sync="dialogVisible"
      height="600px"
      align="bottom"
      close-on-click-modal
    >
      <q-table
        :data="tableData"
        :columns="tableColumns"
        row-key="id"
        style="height: 100%"
        class="myTable scroll"
        hide-bottom
        :pagination="pagination2"
        no-data-label="暂无数据"
        color="primary"
      >
      </q-table>
    </Drawer>
  </div>
</template>

<script>
import Unfold from 'src/components/unfold'
import TreeList from 'src/components/tree-list/list'
import SelectInput from 'src/components/select-input'
import Position from './components/position'
import ProgressDialog from './components/progress-dialog'
import ProgressResultDialog from './components/progress-result-dialog'
import FileItem from './components/file-item'
import FileItemTr from './components/file-item-tr'
import CodeEdit from 'src/components/code-edit/index'
import CloudFileDialog from './components/cloud-file-dialog'
import CloudSelDir from './components/cloud-sel-dir'
import {
  getOffsetLeft,
  getOffsetTop,
  defaultSchemesClearer,
  getFiletype,
  mqttErrMessage,
  matchFileType,
  isUploadFile,
  Base64Decoder,
  Base64Encoder
} from 'src/assets/js/util'
import {
  loadProgressSuccessRecord,
  loadProgressFailRecord,
  saveProgressSuccessRecord,
  saveProgressFailRecord,
  clearProgressSuccessRecord,
  clearProgressFailRecord
} from 'src/assets/js/storage'
import { getOrganizeNestedNew } from 'src/boot/factory/organize'
import { getEquipmentAccount } from 'src/boot/program-v2/G-gov'
import {
  getFileInfo,
  newCncDir,
  newBoxDir,
  cncToBox,
  delCncfile,
  delBoxfile,
  renameCncfile,
  renameBoxfile,
  postFileLog
} from 'src/boot/program-v2/machine'
import {
  filelocalToMachine,
  machineNewFile,
  fileMachineLocal,
  fileMachineCloud,
  getNewBox
} from 'src/boot/program-v2/program-transfer'
import {
  readFile,
  cloudFileExist,
  getDownloadRecord,
  getBasisUrl
} from 'src/boot/program-v2/cloud'
import { writeFile } from 'src/assets/js/file-dir'
import fileMqttMixin from 'src/assets/js/webSocket'
import boxCodeErr from 'src/assets/json/boxCodeErr'
import boxErr from 'src/assets/json/boxErr'
import { date } from 'quasar'
import { mapGetters } from 'vuex'
import moment from 'moment'
import _ from 'lodash'
import Drawer from 'src/components/drawer/drawer'
import { programFormatData } from './data'
import SIGNMIXIN from './sign-mixin'
import { getViewPrivilegeId } from '../../assets/js/enums'
const base64Decoder = new Base64Decoder()
const base64Encoder = new Base64Encoder()
export default {
  name: 'program-transfer',
  mixins: [fileMqttMixin, SIGNMIXIN],
  data () {
    return {
      dialogVisible: false,
      tableColumns: [
        { name: 'id', field: 'id', label: '序号', align: 'left' },
        { name: 'brand', field: 'brand', label: '品牌', align: 'left' },
        { name: 'series', field: 'series', label: '系列', align: 'left' },
        { name: 'format', field: 'format', label: '格式要求', align: 'left' },
        { name: 'suffix', field: 'suffix', label: '文件后缀', align: 'left' },
        { name: 'contents', field: 'contents', label: '目录', align: 'left' },
        { name: 'remark', field: 'remark', label: '备注', align: 'left' }
      ],
      pagination2: {
        rowsPerPage: 0
      },
      tableData: programFormatData,
      deviceIdItem: null,
      lookStatus: 'bigIcon', // 查看状态, list or bigIcon
      treeList: [], // 左侧树结构数据
      treeActItem: [], // 选中的树
      searchCondition: [
        // 搜索选项
        { id: 'number', name: '设备编号' },
        { id: 'technician', name: '数控系统' }
      ],
      searchBy: null,
      keyword: null,
      // 列表位置
      selPathList: [], // 选中路径的位置
      loading: false, // 是否是加载状态
      actFile: [], // 选中的文件
      clickTime: null, // 区分单击与双击
      files: [], // 右侧的数据
      positionType: 'machine', // 判断当前位置是机床、内外部存储和文件列表 machine or store or file
      // 编辑内容
      editFileContent: '', // 要编辑文件的内容
      editFileName: '', // 要编辑文件的名字
      editFileSize: '', // 要编辑文件的大小
      edtiFileDecode: '', // 要编辑文件的编码
      editFilePath: '', // 要编辑文件的路径
      codeState: 'edit', // 添加编辑状态，state or add
      // 表格配置
      columns: [
        // 列表的头部
        {
          name: 'label',
          align: 'left',
          label: '文件名',
          field: 'label',
          style: 'width: 60%'
        },
        { name: 'size', align: 'left', label: '大小', field: 'size' },
        {
          name: 'timestamp',
          label: '修改时间',
          field: 'timestamp',
          sortable: true
        }
      ],
      pagination: {
        sortBy: 'timestamp',
        descending: true,
        page: 1,
        rowsPerPage: 0,
        rowsNumber: 10
      },
      isDeleteId: '',
      isShowInnerLoading: false,
      // 框选数据
      parentW: 0, // 外框的宽
      parentH: 0, // 外框的高
      parentX: 0, // 外框的横坐标
      parentY: 0, // 外框的中坐标
      statPos: 'localCloud', // 定义埋点位置
      dragItem: [], // 存储拖动的数据
      // 传输数据
      progressFiles: [], // 正在传输的文件
      doingProgressFiles: [], // 正在传输的列表
      successProgressFiles: [], // 传输成功的列表
      failProgressFiles: [], // 传输失败的列表
      progressTime: null, // 存储定时器
      programArr: [], // 传输到机器文件列表的数据暂存
      transfering: false // 是否在传输中
    }
  },
  computed: {
    position () {
      // 当前位置
      let path = this.selPathList.reduce((total, item) => {
        return total + '/' + item.label
      }, '')
      return path
    },
    ...mapGetters(['userInfo'])
  },
  created () {
    this.getTree()
    this.getEquipmentAccount()
    this.successProgressFiles = this.sortRecord(
      loadProgressSuccessRecord(this.userInfo.tenant_id)
    )
    this.failProgressFiles = this.sortRecord(
      loadProgressFailRecord(this.userInfo.tenant_id)
    )
  },
  methods: {
    /**
     * 全局刷新数据
     * author: xueli
     */
    refreshInfo () {
      this.lookStatus = 'bigIcon'
      this.treeActItem = []
      this.$refs.treeList.clearAct()
      this.selPathList = []
      this.actFile = []
      // this.positionType = 'machine'
      this.pagination = {
        sortBy: 'timestamp',
        descending: true,
        page: 1,
        rowsPerPage: 0,
        rowsNumber: 10
      }
      this.progressFiles = [] // 正在传输的文件
      this.doingProgressFiles = [] // 正在传输的列表
      this.progressTime = null // 存储定时器
      this.programArr = [] // 传输到机器文件列表的数据暂存
      this.transfering = false // 是否在传输中
      this.clearSearchVal()
      this.getTree()
      this.successProgressFiles = this.sortRecord(
        loadProgressSuccessRecord(this.userInfo.tenant_id)
      )
      this.failProgressFiles = this.sortRecord(
        loadProgressFailRecord(this.userInfo.tenant_id)
      )
    },
    // 获取组织架构数据
    getTree () {
      const cncId = getViewPrivilegeId('programTransfer')
      getOrganizeNestedNew(cncId).then(res => {
        this.treeList = res.data
        this.treeListCopy = defaultSchemesClearer.clear(res.data)
      })
    },
    // 获取设备列表
    getEquipmentAccount () {
      const params = {
        searchBy: this.searchBy || undefined,
        keyword: this.keyword || undefined,
        ifBuildBox: true,
        schemeId:
          this.treeActItem.length > 0 ? this.treeActItem[0].id : undefined,
        schemeLevel:
          this.treeActItem.length > 0 ? this.treeActItem[0].level : undefined,
        statusCode: 1
      }
      this.isShowInnerLoading = true
      getEquipmentAccount(params)
        .then(res => {
          this.files = res.data.list.map(item => {
            return {
              ...item,
              label: `${item.name}(${item.assetNumber})`,
              value: item.boxStrId,
              position: 'machine',
              type: 'machine',
              isFile: true
            }
          })
          // this.files = this.$utils.sortByAny(this.files, 'assetNumber')
          // 设置当前坐在的位置类型
          this.positionType = 'machine'
          this.isShowInnerLoading = false
        })
        .catch(() => {
          this.isShowInnerLoading = false
        })
    },
    // 设置左侧树选中项
    setAct (item) {
      this.treeActItem = [item]
      this.selPathList = [item]
      this.getEquipmentAccount()
    },

    // 刷新
    refreshFun () {
      if (this.selPathList.length === 0) {
        this.getEquipmentAccount()
        this.lookStatus = 'bigIcon'
      } else {
        let nodeAct = this.selPathList[this.selPathList.length - 1]
        if (nodeAct.hasOwnProperty('hash')) {
          this.actFile = []
          this.getEquipmentAccount()
          this.lookStatus = 'bigIcon'
        } else if (nodeAct.type === 'machine') {
          this.actFile = []
          this.getStore(nodeAct)
          this.lookStatus = 'bigIcon'
        } else {
          this.actFile = []
          this.getFiles(nodeAct.path)
        }
      }
    },
    // 返回
    back () {
      if (this.selPathList.length === 0) return
      this.selPathList.pop()
      this.refreshFun()
    },
    /**
     * 路径点击跳转到相应位置
     * 设备列表 type machine
     * 内外部存储 type store
     * 设备文件列表 type orter && 有timestamp属性
     * */
    goto (pathIndex) {
      console.log(pathIndex)
      console.log(this.selPathList)
      this.selPathList = this.selPathList.slice(0, pathIndex)
      console.log(this.selPathList)
      this.refreshFun()
    },
    // 切换显示模式
    changeLookStatus () {
      this.lookStatus = this.lookStatus === 'list' ? 'bigIcon' : 'list'
      this.pagination.sortBy = 'timestamp'
      this.pagination.descending = true
      this.refreshFun()
    },
    // 输入框搜索
    inputSearch (searchBy, keyword) {
      this.searchBy = searchBy.id
      this.keyword = keyword
      this.getEquipmentAccount()
    },
    // 清除搜索条件
    clearSearchVal () {
      this.searchBy = null
      this.keyword = null
      this.getEquipmentAccount()
    },

    // 单击选中文件，按住shift、ctrl多选
    selFiles (e, item) {
      clearTimeout(this.clickTime)
      this.clickTime = setTimeout(() => {
        if (e.ctrlKey) {
          // 按住ctrl键
          const index = this.actFile.findIndex(file => {
            return file.id === item.id
          })
          if (index > -1) {
            this.actFile = this.actFile.filter(file => {
              return file.id !== item.id
            })
          } else {
            this.actFile.push(item)
          }
        } else if (e.shiftKey) {
          // 按住shift键
          if (this.actFile.length === 0) {
            this.actFile.push(item)
          } else {
            const maxIndex = this.getMaxIndex()
            const index = this.files.findIndex(file => {
              return file.id === item.id
            })
            let actFile = this.files.filter((file, fileIndex) => {
              const condition =
                (index > maxIndex &&
                  fileIndex <= index &&
                  fileIndex >= maxIndex) ||
                (index < maxIndex &&
                  fileIndex >= index &&
                  fileIndex <= maxIndex) ||
                (index === maxIndex && fileIndex === index)
              return condition
            })
            this.actFile = actFile
          }
        } else {
          // 单选
          const index = this.actFile.findIndex(file => {
            return file.id === item.id
          })
          this.actFile = index > -1 ? [] : [item]
        }
      }, 250)
    },
    // 选中一个文件
    setFile (item) {
      this.actFile = [item]
    },
    // 是否是选中状态
    isActDay (file) {
      const index = this.actFile.findIndex(item => {
        return item.id === file.id
      })
      return index > -1
    },
    // 清空选中文件列表
    clearActFile (event) {
      this.actFile = []
    },
    // 双击进入子级文件夹
    dblclickE (item) {
      clearTimeout(this.clickTime)
      if (item.type === 'machine') {
        // 当前是机器列表页
        this.actFile = []
        this.selPathList.push(item)
        this.getStore(item)
      } else if (item.type === 'store') {
        this.actFile = []
        this.selPathList.push(item)
        this.getFiles()
      } else if (!item.isFile) {
        this.actFile = []
        this.selPathList.push(item)
        this.getFiles(item.path)
      }
    },
    // 获取内外部存储数据
    async getStore (opt) {
      console.log(opt)
      if (this.isDeleteId !== opt.id) {
        this.onUnSubscribeBox(this.isDeleteId)
      }
      this.isDeleteId = opt.id
      if (!opt.boxStrId) {
        this.noticeMessage('该设备未绑定盒子')
        return
      }
      this.isShowInnerLoading = true
      let tabList = []
      let fileinfo = type => {
        const member = {
          about: type,
          deviceId: opt.id,
          requestId: this.requestId,
          path: '/'
        }
        return member
      }
      // arams)
      let onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        console.log(data)
        this.selPathList.push(opt)
        this.getStoreData(data, opt, tabList)
      }
      this.onSubscribe(opt.id, onMessageArrived)
      const self = this
      const fileTime = setTimeout(() => {
        if (self.isShowInnerLoading) {
          self.isShowInnerLoading = false
          self.onUnSubscribeBox(opt.id)
          self.selPathList.pop()
        } else {
          clearTimeout(fileTime)
        }
      }, 10000)
      // 请求盒子内部和外部存储信息
      let ret = await getFileInfo(fileinfo())
      const member = ret.data
      fileTime && clearTimeout(fileTime)
      // 来源（0：老盒子，1：新盒子)
      if (member.source === 1) {
        console.log('新盒子内外存储')
        this.getStoreData(member, opt, tabList)
      } else {
        getFileInfo(fileinfo(''))
      }
    },
    // 新型获取内外部存储共同处理方法
    getStoreData (data, opt, tabList) {
      let inside = null,
        external = null
      try {
        if (data.source === 1 || Number(data.request_id) === this.requestId) {
          if (data.code === 200 || data.source === 1 || data.code === '200') {
            // 判断是否有外部存储
            if (data.cnc || data.cncIsExist) {
              inside = {
                boxId: opt.boxStrId,
                id: 1,
                label: '内部存储',
                volumeUse: data.cnc_use || '',
                volume: data.cnc || '',
                source: 'machine',
                position: 'cnc',
                level: 6,
                path: '/',
                type: 'store',
                isFile: true
              }
              tabList.push(inside)
            }
            // 判断是否是内部存储
            if (data.box || data.boxIsExist) {
              external = {
                boxId: opt.boxStrId,
                id: 2,
                label: '外部存储',
                volumeUse: data.box_use || '',
                volume: data.box || '',
                source: 'machine',
                position: 'box',
                level: 6,
                path: '/',
                type: 'store',
                isFile: true
              }
              tabList.push(external)
            }
            this.files = _.sortBy(_.uniqBy(tabList, 'id'), 'id')
            // 设置当前坐在的位置类型
            this.positionType = 'store'
          } else {
            console.error('获取列表失败')
            this.errMessage(`获取列表失败,${boxCodeErr[data.code]}`)
          }
          this.isShowInnerLoading = false
        }
      } catch (e) {
        console.error(e)
        this.errMessage('获取列表失败')
        this.isShowInnerLoading = false
        this.selPathList.pop()
      }
      // this.onUnSubscribeBox(opt.id)
      this.selPathList = _.uniqBy(this.selPathList, 'id')
    },
    // 获取文件列表
    /**
     * 点击内外部存储信息 获取文件列表
     */
    async getFiles (path = '/') {
      // 单个设备条件.
      console.log(this.selPathList)
      let selPath = this.selPathList[this.selPathList.length - 1]
      let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
      let params = {
        about: selPath.position,
        deviceId: deviceIdItem.id,
        requestId: this.requestId,
        path: path
      }
      this.isShowInnerLoading = true
      let onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        this.getFilesData(data, params, deviceIdItem.id)
      }
      this.onSubscribe(deviceIdItem.id, onMessageArrived)
      // 增加时间长不反悔取消loading
      const self = this
      const fileTime = setTimeout(() => {
        if (self.isShowInnerLoading) {
          self.isShowInnerLoading = false
          self.onUnSubscribeBox(deviceIdItem.id)
          self.selPathList.pop()
        } else {
          clearTimeout(fileTime)
        }
      }, 10000)
      let ret = await getFileInfo(params)
      const member = ret.data
      fileTime && clearTimeout(fileTime)
      console.log('文件列表', member)
      if (member.source === 1) {
        this.getFilesDataNew(member.response, params)
      }
    },
    // 新盒子处理文件列表显示
    getFilesDataNew (data, params) {
      // data.result_code 0 成功, 1 失败
      if (data.result_code === 0) {
        const positon = params.about
        if (positon === 'box') {
          let { dirData, fileData } = this.initMachineNodeData(
            params,
            data.paras,
            'box',
            true
          )
          this.files =
            this.lookStatus === 'bigIcon' ||
            (this.lookStatus === 'list' &&
              this.pagination.sortBy &&
              this.pagination.descending)
              ? [].concat(dirData, fileData)
              : [].concat(fileData, dirData)
        }
        if (positon === 'cnc') {
          let { dirData, fileData } = this.initMachineNodeData(
            params,
            data.paras.result_content,
            'cnc',
            true
          )
          this.files =
            this.lookStatus === 'bigIcon' ||
            (this.lookStatus === 'list' &&
              this.pagination.sortBy &&
              this.pagination.descending)
              ? [].concat(dirData, fileData)
              : [].concat(fileData, dirData)
        }
        this.positionType = 'file'
      } else {
        this.errMessage('获取新盒子列表失败')
        this.selPathList.pop()
      }
      this.isShowInnerLoading = false
    },
    // 获取文件列表公共 处理方法
    getFilesData (data, params, deviceId) {
      try {
        if (
          data.request_id === this.requestId ||
          Number(data.request_id) === this.requestId
        ) {
          if (data.code === 200 || data.code === '200') {
            // 判断是否有外部存储
            if (data.hasOwnProperty('box')) {
              let { dirData, fileData } = this.initMachineNodeData(
                params,
                data.box,
                'box'
              )
              this.files =
                this.lookStatus === 'bigIcon' ||
                (this.lookStatus === 'list' &&
                  this.pagination.sortBy &&
                  this.pagination.descending)
                  ? [].concat(dirData, fileData)
                  : [].concat(fileData, dirData)
            }
            if (data.hasOwnProperty('cnc')) {
              let { dirData, fileData } = this.initMachineNodeData(
                params,
                data.cnc,
                'cnc'
              )
              this.files =
                this.lookStatus === 'bigIcon' ||
                (this.lookStatus === 'list' &&
                  this.pagination.sortBy &&
                  this.pagination.descending)
                  ? [].concat(dirData, fileData)
                  : [].concat(fileData, dirData)
            }

            // 设置当前所在的位置类型
            this.positionType = 'file'
          } else {
            console.log('获取列表失败')
            this.errMessage(`获取列表失败,${boxCodeErr[data.code]}`)
          }
          this.isShowInnerLoading = false
          this.onUnSubscribeBox(deviceId)
        }
      } catch (e) {
        console.error(e)
        this.errMessage('获取列表失败')
        this.selPathList.pop()
        this.isShowInnerLoading = false
      }
    },
    // 初始化文件数据
    // 获取内外存储信息初始化文件列表
    // return dirData文件夹列表 fileData文件列表
    initMachineNodeData (node, info, source, isNewBox) {
      let dirData = [],
        fileData = []
      info.forEach((item, index) => {
        // 文件夹数据
        if (item.type === '0' || item.type === 0) {
          dirData.push({
            id: index + 1,
            boxId: node.boxId,
            label: item.name,
            size: item.size,
            isFile: false,
            icon: 'img:statics/svg/file-icon.svg',
            source: 'machine',
            position: source,
            type: 'other',
            path: node.path + item.name + '/',
            timestamp: parseInt(item.modify_time * 1000)
          })
        } else if (item.type === 1 || item.type === '1') {
          // 文件数据
          let type = getFiletype(item.name)
          fileData.push({
            id: index + 1,
            boxId: node.boxId,
            label: item.name,
            size: item.size,
            isFile: item.type === 1 || item.type === '1',
            icon: 'img:statics/svg/' + type + '.svg',
            source: 'machine',
            position: source,
            type,
            path: node.path + item.name,
            timestamp:
              source === 'cnc' && !isNewBox
                ? moment(item.modify_time * 1000)
                  .add(-8, 'h')
                  .format('YYYY-MM-DD HH:mm')
                : parseInt(item.modify_time * 1000)
          })
        }
      })
      if (this.lookStatus === 'list' && this.pagination.sortBy) {
        let sortBy = this.pagination.sortBy
        let descending = this.pagination.descending
        const sortFn = descending
          ? (a, b) =>
            a[sortBy] > b[sortBy] ? -1 : a[sortBy] < b[sortBy] ? 1 : 0
          : (a, b) =>
            a[sortBy] > b[sortBy] ? 1 : a[sortBy] < b[sortBy] ? -1 : 0
        dirData = dirData.sort(sortFn)
        fileData = fileData.sort(sortFn)
      }
      return { dirData, fileData }
    },
    // 表格排序
    onRequest (props) {
      const { sortBy, descending } = props.pagination
      if (sortBy) {
        const sortFn = descending
          ? (a, b) =>
            a[sortBy] > b[sortBy] ? -1 : a[sortBy] < b[sortBy] ? 1 : 0
          : (a, b) =>
            a[sortBy] > b[sortBy] ? 1 : a[sortBy] < b[sortBy] ? -1 : 0
        let dirs = this.files.filter(item => !item.isFile).sort(sortFn)
        let files = this.files.filter(item => item.isFile).sort(sortFn)
        this.files = descending
          ? [].concat(dirs, files)
          : [].concat(files, dirs)
        this.pagination.sortBy = sortBy
        this.pagination.descending = descending
      }
    },

    // 文件设置相关操作
    // 重命名文件夹、文件
    setNewNameFun (item, rename) {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
      // 如果名字没有变化，就这样了
      if (item.label === rename) {
        item.edit = false
        return
      }
      let newPath = nodeAct.path + '/' + rename + (item.isFile ? '' : '/')
      const requestIdNew = this.getRandom()
      let params = {
        deviceId: deviceIdItem.id,
        requestId: requestIdNew,
        newPath: newPath,
        oldPath: item.path
      }
      const logParams = {
        fileName: item.label,
        filePath: `${
          item.position === 'cnc' ? '内部存储' : '外部存储'
        }${nodeAct.path}${rename}`,
        content: `重命名${rename}`,
        fileSize: item.size,
        onDevice: `${deviceIdItem.name}(${deviceIdItem.assetNumber})`
      }
      // let ret = null
      let ref =
        (this.lookStatus === 'bigIcon' ? 'fileItem' : 'fileItemTr') + item.id
      let onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        console.log(data)
        this.setNewNameFunData(data, ref, item, requestIdNew, deviceIdItem.id)
      }
      this.onSubscribe(deviceIdItem.id, onMessageArrived)
      this.onSubscribeNewBox(requestIdNew, res => {
        let data = JSON.parse(res.body).data
        console.log(data)
        this.setNewNameFunDataNeW(data, ref, item, requestIdNew, logParams)
      })
      if (nodeAct.position === 'cnc') {
        renameCncfile(params)
      } else if (nodeAct.position === 'box') {
        renameBoxfile(params)
      }
      // const member = ret.data
      // if (member.source === 1) {
      //   this.setNewNameFunData(member.response, ref, item, requestIdNew)
      // } else if (member.source === 0) {
      //   this.onSubscribe(deviceIdItem.id, onMessageArrived)
      // } else {
      //   this.errMessage('重命名失败')
      // }
    },
    // 新盒子重命名
    setNewNameFunDataNeW (data, ref, item, requestIdNew, logParams) {
      const self = this
      if (data.cmd_ID === requestIdNew) {
        if (data.errorCode === '3000' || data.state === 0) {
          if (self.$refs[ref].edit) {
            self.$refs[ref].edit = false
          } else {
            self.$refs[ref][0].edit = false
          }
          this.setLog(logParams)
          this.onUnSubscribeNewBox(requestIdNew)
          self.refreshFun()
          // 刷新数据
        } else {
          if (self.$refs[ref].rename) {
            self.$refs[ref].rename = item.label
            self.$refs[ref].edit = false
          } else {
            self.$refs[ref][0].rename = item.label
            self.$refs[ref][0].edit = false
          }
          if (_.has(data, 'errorCode')) {
            mqttErrMessage(data.errorCode)
          } else {
            self.errMessage('重命名失败')
          }
        }
      }
    },
    // 重命名公共
    setNewNameFunData (data, ref, item, requestIdNew, deviceId) {
      let self = this
      try {
        if (Number(data.request_id) === requestIdNew) {
          if (data.code === 200) {
            if (data.error === 0) {
              if (self.$refs[ref].edit) {
                self.$refs[ref].edit = false
              } else {
                self.$refs[ref][0].edit = false
              }
              this.onUnSubscribeBox(deviceId)
              self.refreshFun()
            } else {
              // 报错
              if (self.$refs[ref].rename) {
                self.$refs[ref].rename = item.label
                self.$refs[ref].edit = false
              } else {
                self.$refs[ref][0].rename = item.label
                self.$refs[ref][0].edit = false
              }
              if (data.hasOwnProperty('error')) {
                this.errMessage(boxErr[data.error])
              }
              // 刷新数据
              self.refreshFun()
            }
          } else {
            if (data.hasOwnProperty('code')) {
              this.errMessage(boxCodeErr[data.code])
            }
          }
        }
      } catch (e) {
        console.error(e)
        if (self.$refs[ref].rename) {
          self.$refs[ref].rename = item.label
        } else {
          self.$refs[ref][0].rename = item.label
        }
      }
    },
    // 删除文件和文件夹
    async deleteFun (item) {
      this.$q
        .dialog({
          title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 确定要删除${item.label}吗？</p>`,
          message: '删除后无法恢复',
          html: true,
          ok: {
            unelevated: true,
            label: '确认'
          },
          cancel: {
            unelevated: true,
            outline: true,
            label: '取消'
          }
        })
        .onOk(async () => {
          // 删除订阅
          let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
          const requestIdNew = this.getRandom()
          let params = {
            deviceId: deviceIdItem.id,
            requestId: requestIdNew,
            path: item.path
          }
          const logParams = {
            fileName: item.label,
            filePath: `${item.position === 'cnc' ? '内部存储' : '外部存储'}${
              item.path
            }`,
            content: '删除',
            fileSize: item.size,
            onDevice: `${deviceIdItem.name}(${deviceIdItem.assetNumber})`
          }
          console.log(logParams)
          let onMessageArrived = res => {
            let data = JSON.parse(res.body).data
            console.log(data)
            this.deleteFunData(data, deviceIdItem.id, requestIdNew)
          }
          this.onSubscribe(deviceIdItem.id, onMessageArrived)
          this.onSubscribeNewBox(requestIdNew, res => {
            let data = JSON.parse(res.body).data
            try {
              if (data.cmd_ID === requestIdNew) {
                if (data.state === 0 || data.errorCode === '3000') {
                  this.setLog(logParams)
                  this.$nextTick(() => {
                    this.refreshFun()
                  })
                  // 刷新数据
                } else {
                  if (_.has(data, 'errorCode')) {
                    mqttErrMessage(data.errorCode)
                  } else {
                    this.errMessage('删除失败')
                  }
                }
              }
            } catch (e) {
              console.error(e)
              this.errMessage('删除失败')
            }
          })
          // let ret = null
          if (item.position === 'cnc') {
            delCncfile(params)
          } else if (item.position === 'box') {
            delBoxfile(params)
          }
        })
    },
    // 新老盒子删除共同方法
    deleteFunData (data, deviceId, requestIdNew) {
      try {
        if (Number(data.request_id) === requestIdNew && data.code === 200) {
          if (data.error === 0) {
            this.onUnSubscribeBox(deviceId)
            this.$nextTick(() => {
              this.refreshFun()
            })
            // 刷新数据
          } else {
            mqttErrMessage(data.error)
          }
        }
      } catch (e) {
        console.error(e)
        this.errMessage('删除失败')
      }
    },
    // 编辑读取文件
    editFile (item) {
      if (!this.testFileSize(item)) return
      this.editFileName = item.label
      this.editFileSize = item.size
      if (matchFileType(item.label)) {
        this.errMessage(
          '无法编辑图片文件、word文件、视频文件、音频文件、快捷方式、压缩文件！'
        )
        return
      }
      if (item.position === 'cnc') {
        this.putMachineInside(item)
      } else {
        this.putMachine(item, item.path)
      }
    },
    // 验证文件大小是否超过1M
    testFileSize (file) {
      if (file.size > 1024 * 1024) {
        this.errMessage('文件超过1M暂不支持查看！')
        return false
      }
      return true
    },
    // 开始发送内部存储文件到外部存储文件
    async putMachineInside (send) {
      let requestId1 = this.requestId
      let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
      let params1 = {
        deviceId: deviceIdItem.id,
        cncPath: send.path,
        boxPath: '',
        requestId: requestId1
      }
      let onMessageArrived = res => {
        this.isShowInnerLoading = false
        let data = JSON.parse(res.body).data
        console.log(data)
        try {
          // 这里是放置对其他消息进行处理
          if (
            requestId1 === data.request_id ||
            requestId1 === Number(data.request_id)
          ) {
            if (data.error === 0) {
              this.putMachine(send, data.file_path)
            } else {
              this.errMessage(`文件内容读取失败！${boxErr[data.code]}`)
            }
          }
        } catch (e) {
          console.error('文件内容读取失败！')
        }
      }
      this.isShowInnerLoading = true
      let newBoxList = await getNewBox(deviceIdItem.id)
      if (!_.isEmpty(newBoxList.data)) {
        const boxRemark = newBoxList.data[0].boxRemark
        if (boxRemark === 0) {
          let ret = await cncToBox(params1)
          if (ret.success) {
            if (ret.data.source === 0) {
              this.onSubscribe(deviceIdItem.id, onMessageArrived)
            }
          } else {
            this.transfering = false
          }
        } else {
          // 直接走下载
          this.putMachine(send, send.path)
        }
      }
    },
    // 从机床传输到云端的方法
    // 编辑外部存储文件时触发
    putMachine (send, path) {
      console.log('编辑文件', send, path)
      let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
      const requestIdNew = this.getRandom()
      let params = {
        deviceId: deviceIdItem.id,
        requestId: requestIdNew,
        fileName: send.label,
        filePath: path,
        fromBox: send.position === 'box' ? 1 : 0
      }
      let isNewUlrState = false
      let urlNew = null
      // let requestId
      // 上传开始时间
      let onMessageArrived = res => {
        this.isShowInnerLoading = false
        let data = JSON.parse(res.body).data
        console.log(data)
        try {
          // 这里是放置对其他消息进行处理
          if (requestIdNew === Number(data.request_id)) {
            if (
              data.hasOwnProperty('source') &&
              data.source === 'send_result'
            ) {
              if (data.code === 200) {
                // 盒子上传到云端已完成，接下来是从云端获取内容
                this.getFileContentNew(send, data.url)
              } else {
                this.errMessage(`文件内容读取失败！${boxCodeErr[data.code]}`)
              }
            }
          }
        } catch (e) {
          console.error(e)
          this.errMessage(`文件内容读取失败！`)
        }
      }
      this.isShowInnerLoading = true
      // source 区分新老盒子.
      // 订阅返回URL地址; 去云端下载文件内容 old盒子 new 盒子;
      // 接受异步返回消息进行下载文件
      this.onSubscribe2(requestIdNew, onMessageArrived)
      this.onSubscribeNewBox(requestIdNew, mes => {
        this.isShowInnerLoading = false
        let data = JSON.parse(mes.body).data
        console.log(data)
        if (data.cmd_ID === requestIdNew) {
          if (data.errorCode === '2000' || data.errorCode === '3000') {
            isNewUlrState = true
            if (!_.isNil(urlNew)) {
              this.getFileContentNew(send, urlNew)
            }
          } else {
            mqttErrMessage(data.errorCode)
          }
          this.onUnSubscribeNewBox(requestIdNew)
        }
      })
      fileMachineLocal(params)
        .then(res => {
          // requestId = res.data.requestId
          urlNew = res.data.url
          if (res.data.source === '1') {
            if (requestIdNew === Number(res.data.requestId)) {
              if (isNewUlrState) {
                this.getFileContentNew(send, res.data.url)
              }
            }
          }
        })
        .catch(() => {
          this.isShowInnerLoading = false
        })
    },
    // new de
    getFileContentNew (send, url) {
      const params = {
        cloudPath: url
      }
      getDownloadRecord(params).then(res => {
        const dataString = base64Decoder.decode(res.data)
        console.log(dataString)
        this.editFileContent = dataString
        this.editFilePath = send.path
        this.codeState = 'edit'
        this.$refs.codeEdit.showDialog()
      })
    },
    // 通过云端接口读取云端文件内容
    getFileContent (send, sendPath) {
      readFile(sendPath).then(res => {
        this.editFileContent = res.data
        this.editFilePath = send.path
        this.codeState = 'edit'
        this.$refs.codeEdit.showDialog()
      })
    },
    // 保存文件
    saveFile (path, code) {
      if (code.length === 0) {
        this.noticeMessage('设备里文件内容不能为空！')
        return
      }
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      if (nodeAct.position === 'cnc' && this.codeState === 'edit') {
        this.delEditFile(path, code)
      } else {
        this.saveFileFuc(path, code)
      }
    },
    // 编辑操作，保存时，先删掉内部存储对应的文件
    async delEditFile (path, code) {
      let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
      // let nodeAct = this.selPathList[this.selPathList.length - 1]
      const requestIdNew = this.getRandom()
      let params = {
        deviceId: deviceIdItem.id,
        requestId: requestIdNew,
        path: path
      }
      let onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        console.log(data)
        this.delEditFileData(path, data, code, requestIdNew)
      }
      this.onSubscribe(deviceIdItem.id, onMessageArrived)
      let ret = await delCncfile(params)
      const member = ret.data
      if (member.source === 1) {
        if (member.response.result_code === 0) {
          this.saveFileFuc(path, code)
        }
      }
    },
    // 保存文件时删除公用方法
    delEditFileData (path, data, code, requestIdNew) {
      try {
        if (Number(data.request_id) === requestIdNew && data.code === 200) {
          if (data.error === 0) {
            // 刷新数据
            this.saveFileFuc(path, code)
          } else {
            mqttErrMessage(data.error)
          }
        }
      } catch (e) {
        console.error(e)
        this.errMessage('保存失败')
      }
    },
    // 添加文件
    saveFileFuc (path, code) {
      console.log(path, code)
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
      const requestIdNew = this.getRandom()
      const dataString = base64Encoder.encode(code)
      let params = {
        deviceId: deviceIdItem.id,
        requestId: requestIdNew,
        content: dataString,
        fileName: this.editFileName,
        storagePath: nodeAct.path,
        toCnc: nodeAct.position === 'cnc' ? 1 : 0
      }
      const logParams = {
        fileName: this.editFileName,
        filePath: `${
          nodeAct.position === 'cnc' ? '内部存储' : '外部存储'
        }${path}`,
        content: '编辑',
        fileSize: this.editFileSize,
        onDevice: `${deviceIdItem.name}(${deviceIdItem.assetNumber})`
      }
      let oldBoxMes = []
      let onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        console.log(data)
        try {
          if (requestIdNew === Number(data.request_id)) {
            if (
              data.destinationName ===
              `${
                this.CommonConfig.socketConfig.SOCKET_TOPIC.machineFileInfo
                  .subscribeTopic
              }${deviceIdItem.id}`
            ) {
              oldBoxMes.push({
                code: data.code,
                error: _.isNil(data.error) ? 0 : data.error
              })
            }
            if (data.source === 'send_result') {
              oldBoxMes.push({
                code: data.code,
                error: _.isNil(data.error) ? 0 : data.error
              })
            }
          }
          this.$nextTick(() => {
            console.log(oldBoxMes)
            if (oldBoxMes.length === 2) {
              if (oldBoxMes.some(v => v.code !== 200)) {
                const code = oldBoxMes.filter(v => v.code !== 200)[0].code
                this.errMessage(
                  `${this.codeState === 'edit' ? '修改' : '添加'}文件${
                    this.editFileName
                  }失败！${boxCodeErr[code]}`
                )
              } else if (oldBoxMes.some(v => v.error !== 0)) {
                const error = oldBoxMes.filter(v => v.error !== 0)[0].error
                this.errMessage(
                  `${this.codeState === 'edit' ? '修改' : '添加'}文件${
                    this.editFileName
                  }失败！${boxErr[error]}`
                )
              } else {
                let successMessage = `${
                  this.codeState === 'edit' ? '修改' : '添加'
                }文件${this.editFileName}成功`
                this.$message.success(successMessage)
              }
            } else {
            }
            this.refreshFun()
          })
        } catch (e) {
          console.error(e)
        }
        this.onUnSubscribeResultBox(requestIdNew)
      }
      let onMessageArrivedNew = res => {
        this.isShowInnerLoading = false
        let data = JSON.parse(res.body).data
        console.log(data)
        try {
          if (requestIdNew === data.cmd_ID) {
            // 判断外部存储新建文件完成
            if (data.errorCode === '2000' || data.errorCode === '3000') {
              let successMessage = `${
                this.codeState === 'edit' ? '修改' : '添加'
              }文件${this.editFileName}成功`
              this.$message.success(successMessage)
              this.codeState === 'edit' && this.setLog(logParams)
              this.refreshFun()
            } else if (data.errorCode !== '2000' && data.errorCode !== '3000') {
              this.errMessage(
                `${this.codeState === 'edit' ? '修改' : '添加'}文件${
                  this.editFileName
                }失败！${boxErr[data.errorCode]}`
              )
            }
            // 判断内部存储新建文件完成
          }
        } catch (e) {
          console.error(e)
        }
      }
      this.onSubscribeNewBox(requestIdNew, onMessageArrivedNew)
      this.onSubscribe2(requestIdNew, onMessageArrived)
      // 编辑创建文件,新老盒子逻辑一样
      machineNewFile(params).then(res => {
        const ret = res.data
        if (ret.source === '1') {
          this.isShowInnerLoading = true
        }
        if (nodeAct.position === 'cnc' && ret.source === '0') {
          this.onSubscribe(deviceIdItem.id, onMessageArrived)
        }
        this.editFileContent = ''
        this.$refs.codeEdit.hideDialog()
      })
    },

    // 新建操作
    // 新建文件夹
    newFolder () {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
      this.$q
        .dialog({
          class: 'prompt-dialog',
          title: '文件夹名称',
          prompt: {
            model: '',
            type: 'text'
          },
          ok: {
            unelevated: true,
            label: '确认'
          },
          cancel: {
            unelevated: true,
            outline: true,
            label: '取消'
          },
          persistent: true
        })
        .onOk(async res => {
          let data = res.trim()
          if (data.length === 0) {
            this.$message.warning('名称不能为空')
            return false
          }
          if (data.length > 20) {
            this.$message.warning('名称长度必须小于20')
            return false
          }
          let findIndex = this.files.findIndex(
            item => !item.isFile && item.label === data
          )
          if (findIndex > -1) {
            this.$message.warning(`文件夹${data}已存在`)
            return false
          }
          const requestIdNew = this.getRandom()
          let params = {
            deviceId: deviceIdItem.id,
            requestId: requestIdNew,
            path: nodeAct.path + data
          }
          let ret
          if (nodeAct.position === 'cnc') {
            ret = await newCncDir(params)
          } else if (nodeAct.position === 'box') {
            ret = await newBoxDir(params)
          }
          let onMessageArrived = res => {
            let data = JSON.parse(res.body).data
            console.log(data)
            try {
              if (
                Number(data.request_id) === requestIdNew &&
                data.code === 200
              ) {
                if (data.error === 0) {
                  // 刷新数据
                  this.refreshFun()
                } else {
                  mqttErrMessage(data.error)
                }
              }
            } catch (e) {
              console.error(e)
              this.errMessage('新建文件夹失败')
            }
          }
          let onMessageArrivedNew = res => {
            let data = JSON.parse(res.body).data
            console.log(data)
            try {
              if (data.cmd_ID === requestIdNew) {
                if (data.state === 0 || data.errorCode === '3000') {
                  // 刷新数据
                  this.refreshFun()
                } else {
                  this.errMessage('新建文件夹失败')
                }
              }
            } catch (e) {
              console.error(e)
              this.errMessage('新建文件夹失败')
            }
          }
          if (ret.data.source === 0) {
            this.onSubscribe(deviceIdItem.id, onMessageArrived)
          } else {
            this.onSubscribeNewBox(requestIdNew, onMessageArrivedNew)
          }
        })
    },
    // 新建文件
    newFile () {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      this.$q
        .dialog({
          class: 'prompt-dialog',
          title: '文件名称',
          prompt: {
            model: '',
            type: 'text'
          },
          ok: {
            unelevated: true,
            label: '确认'
          },
          cancel: {
            unelevated: true,
            outline: true,
            label: '取消'
          },
          persistent: true
        })
        .onOk(res => {
          let data = res.trim()
          if (data.length === 0) {
            this.$message.warning('名称不能为空')
            return false
          }
          if (data.length > 20) {
            this.$message.warning('名称长度必须小于20')
            return false
          }
          if (isUploadFile(data)) {
            this.$message.warning(`该类型文件无法新建`)
            return false
          }

          let findIndex = this.files.findIndex(
            item => item.isFile && item.label === data
          )
          if (findIndex > -1) {
            this.$message.warning(`文件${data}已存在`)
            return false
          }
          this.editFilePath = nodeAct.path + data
          this.editFileName = data
          this.editFileContent = ''
          this.edtiFileDecode = ''
          this.codeState = 'add'
          this.$refs.codeEdit.showDialog()
        })
    },

    // 文件传输
    // 多设备文件传输
    // 显示本地选择文件件弹框
    testMachineNum (event) {
      if (this.actFile.length === 0) {
        this.noticeMessage('请先选择要传输到设备位置')
        if (event.preventDefault) {
          event.preventDefault()
        } else {
          event.returnValue = false
        }
      }
    },
    /**
     * 本地上传
     * event input事件
     * position 传输位置，cnc or box
     */
    uploadManyLocalFile (event, position) {
      const files = event.target.files
      // 传输前的验证
      if (!this.testUploadLocalFile(files)) {
        return
      }
      this.actFile.forEach(machine => {
        for (let i = 0; i < files.length; i++) {
          let file = files[i]
          if (isUploadFile(file.name)) {
            this.errMessage('该类型文件无法上传！')
            break
          }
          // 添加到传输队列
          this.addMachineProgramArr(machine, file, 'local', position)
        }
      })
      this.startProgram()
      event.target.value = ''
    },
    /**
     * 设备页面添加到传输列表
     */
    addMachineProgramArr (machine, sendFile, sendSource, machinePosition) {
      this.programArr.push({
        machine,
        sendFile,
        sendSource,
        machinePosition,
        sendStatus: 'many' // 发送时处于设备列表页
      })
      let startTime = new Date()
      let progress = {
        name: sendSource === 'local' ? sendFile.name : sendFile.label, // 文件名字
        progress: 0, // 传输进度
        state: 'upload', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: 16, // 每次上传的大小
        fileSize: 0, // 文件总大小
        acceptPath: '/', // 接收方地址
        startTime, // 开始时间
        sender: sendSource, // 发送方
        acceptor: `machine(${
          machinePosition === 'cnc' ? '内部存储' : '外部存储'
        })`, // 接收方
        endTime: this.dateToString(new Date()),
        useTime: this.getUseTime(startTime, new Date()),
        boxId: machine.boxStrId
      }
      this.addProgressFiles(progress)
    },

    // 单设备文件传输
    // 本地上传到机床
    //  本地发送.
    uploadLocalFile (event) {
      const files = event.target.files
      // 传输前的验证
      if (!this.testUploadLocalFile(files)) {
        return
      }
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      for (let i = 0; i < files.length; i++) {
        let file = files[i]
        if (isUploadFile(file.name)) {
          this.errMessage('该类型文件无法上传！')
          break
        }
        if (this.machineFileExist(nodeAct.path, file.name)) {
          if (nodeAct.position === 'cnc') {
            this.$q.dialog({
              title: `<p class="dialog-notice-title"><i class="iconfont icontubiao-28" ></i> 提示</p>`,
              message: '文件' + file.name + '已存在，内部存储不允许覆盖文件',
              html: true,
              ok: {
                unelevated: true,
                label: '确认'
              },
              persistent: true
            })
          } else {
            this.$q
              .dialog({
                title: `<p class="dialog-notice-title"><i class="iconfont icontubiao-28" ></i> 提示</p>`,
                message: `文件${file.name}已存在，是否覆盖文件?`,
                html: true,
                ok: {
                  unelevated: true,
                  label: '确认'
                },
                cancel: {
                  unelevated: true,
                  outline: true,
                  label: '取消'
                },
                persistent: true
              })
              .onOk(data => {
                // 添加到传输队列
                this.addProgramArr(
                  file,
                  nodeAct.path,
                  'local',
                  `machine(${
                    nodeAct.position === 'cnc' ? '内部存储' : '外部存储'
                  })`,
                  nodeAct.path
                )
                // 开始下载
                this.startProgram()
              })
          }
        } else {
          // 添加到传输队列
          this.addProgramArr(
            file,
            nodeAct.path,
            'local',
            `machine(${nodeAct.position === 'cnc' ? '内部存储' : '外部存储'})`,
            nodeAct.path
          )
        }
      }
      // 开始下载
      this.startProgram()
      event.target.value = ''
    },
    // 发送本地文件到机器的方法
    putLocalToMachine (program) {
      let self = this
      let nodeAct = program.nodeAct
      // 获取当前发送信息
      // let requestId
      let deviceIdItem =
        this.selPathList.find(v => v.type === 'machine') || program.machine
      let startTime = new Date()
      let formdata = new FormData()
      let position, acceptPath, boxId
      // 上一个进度
      let lastProgress = null,
        filesize = program.sendFile.size
      if (program.sendStatus === 'single') {
        position = nodeAct.position
        boxId = nodeAct.boxId
        acceptPath =
          position === 'cnc'
            ? nodeAct.path + program.sendFile.name
            : nodeAct.path + program.sendFile.name
      } else {
        position = program.machinePosition
        boxId = program.machine.boxStrId
        acceptPath = position === 'cnc' ? '/' : '/' + program.sendFile.name
      }
      let progress = {
        name: program.sendFile.name, // 文件名字
        progress: 0, // 传输进度
        state: 'success', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: 16, // 每次上传的大小
        fileSize: filesize, // 文件总大小
        acceptPath, // 接收方地址
        startTime, // 开始时间
        sender: program.sendSource, // 发送方
        acceptor: `machine(${position === 'cnc' ? '内部存储' : '外部存储'})`, // 接收方
        endTime: self.dateToString(new Date()),
        useTime: self.getUseTime(startTime, new Date())
      }
      const requestIdNew = this.getRandom()
      formdata.append('deviceId', deviceIdItem.id)
      formdata.append('requestId', requestIdNew)
      formdata.append('file', program.sendFile)
      formdata.append('storagePath', acceptPath)
      formdata.append('toCnc', position === 'cnc' ? 1 : 0)
      formdata.append('fileName', program.sendFile.name)
      const logParams = {
        fileName: progress.name,
        filePath: `${position === 'cnc' ? '内部存储' : '外部存储'}${
          progress.acceptPath
        }`,
        content: program.sendStatus === 'single' ? '发送' : '发送',
        fileSize: progress.fileSize,
        onDevice: `${deviceIdItem.name}(${deviceIdItem.assetNumber})`
      }
      let onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        console.log(data)
        try {
          if (requestIdNew === Number(data.request_id)) {
            // 内部存储逻辑，当data.err===0才是传输成功
            if (position === 'cnc') {
              // 判断是内部存储发来的消息
              if (
                data.destinationName ===
                `${
                  this.CommonConfig.socketConfig.SOCKET_TOPIC.machineFileInfo
                    .subscribeTopic
                }${deviceIdItem.id}`
              ) {
                if (data.hasOwnProperty('error') && data.error === 0) {
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'success'
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                  // 传输成功，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  // 上传成功，刷新列表
                  if (program.sendStatus === 'single') {
                    this.refreshFun()
                  }
                } else {
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = data.hasOwnProperty('error')
                    ? boxErr[data.error]
                    : boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  self.addProgressFiles(progress)
                }
              } else if (
                data.hasOwnProperty('source') &&
                data.source === 'send_result'
              ) {
                if (data.code !== 200) {
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  self.addProgressFiles(progress)
                } else {
                  this.transfering = false
                }
              } else if (
                lastProgress === null ||
                lastProgress.progress < data.rate
              ) {
                // 这里是防止顺序错乱
                progress.progress = data.rate
                progress.state = 'upload'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                lastProgress = progress
                self.addProgressFiles(progress)
              }
            } else {
              // 外部存储逻辑，当data.code===200才是传输成功
              if (
                data.hasOwnProperty('source') &&
                data.source === 'send_result'
              ) {
                if (data.code === 200) {
                  // 本地发送存储到操作日志中
                  this.setLog({
                    fileName: progress.name,
                    filePath: `${position === 'cnc' ? '内部存储' : '外部存储'}${
                      progress.acceptPath
                    }`,
                    content: '发送',
                    fileSize: progress.fileSize,
                    onDevice: `${deviceIdItem.name}(${
                      deviceIdItem.assetNumber
                    })`
                  })
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'success'
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  self.addProgressFiles(progress)
                  // 上传成功，刷新列表
                  // 传输成功，开始传下一个
                  self.transfering = false
                  // 上传成功，刷新列表
                  if (program.sendStatus === 'single') {
                    this.refreshFun()
                  }
                  self.startProgram()
                } else {
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  self.addProgressFiles(progress)
                }
              }
            }
          }
        } catch (e) {
          console.error(e)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          // 报告进度
          progress.progress = 1
          progress.state = 'fail'
          progress.reason = '网络繁忙'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          self.addProgressFiles(progress)
        }
        this.onUnSubscribeResultBox(requestIdNew)
      }
      let onMessageArrivedNew = res => {
        let data = JSON.parse(res.body).data
        console.log(data)

        try {
          if (requestIdNew === data.cmd_ID) {
            // 内部存储逻辑，当data.err===0才是传输成功
            if (position === 'cnc') {
              // 判断是内部存储发来的消息
              if (data.errorCode === '3000') {
                // 本地发送存储到操作日志中
                this.setLog(logParams)
                // 报告进度
                progress.progress = 1
                progress.state = 'success'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                this.addProgressFiles(progress)
                // 传输成功，开始传下一个
                this.transfering = false
                this.startProgram()
                // 上传成功，刷新列表
                if (program.sendStatus === 'single') {
                  this.refreshFun()
                }
              } else {
                // 传输失败，开始传下一个
                this.transfering = false
                this.startProgram()
                // 报告进度
                progress.progress = 1
                progress.state = 'fail'
                progress.reason = boxCodeErr[data.errorCode] || '网络异常'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                self.addProgressFiles(progress)
              }
            } else {
              // 外部存储逻辑，当data.code===200才是传输成功
              if (data.errorCode === '2000') {
                if (data.state === 0) {
                  // 本地发送存储到操作日志中
                  this.setLog(logParams)
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'success'
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  // 上传成功，刷新列表
                  // 传输成功，开始传下一个
                  self.transfering = false
                  self.startProgram()
                  self.addProgressFiles(progress)
                  // 上传成功，刷新列表
                  if (program.sendStatus === 'single') {
                    this.refreshFun()
                  }
                } else {
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = boxCodeErr[data.errorCode]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  self.addProgressFiles(progress)
                }
              } else if (lastProgress === null) {
                // 这里是防止顺序错乱
                progress.progress = 1
                progress.state = 'fail'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                lastProgress = progress
                self.addProgressFiles(progress)
              }
            }
          }
        } catch (e) {
          console.error(e)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          // 报告进度
          progress.progress = 1
          progress.state = 'fail'
          progress.reason = '网络繁忙'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          self.addProgressFiles(progress)
        }
        this.onUnSubscribeNewBox(requestIdNew)
      }
      if (position === 'cnc') {
        this.onSubscribe(deviceIdItem.id, onMessageArrived)
      }
      // 发送到多台的数据标识
      if (program.sendStatus === 'many') {
        progress.boxId = boxId
      }
      // 发送到多台的数据标识
      this.onSubscribeNewBox(requestIdNew, onMessageArrivedNew)
      this.onSubscribe2(requestIdNew, onMessageArrived)
      filelocalToMachine(formdata).then(res => {
        if (res.data.hasOwnProperty('requestId')) {
        } else {
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          // 报告进度
          progress.progress = 1
          progress.state = 'fail'
          progress.reason = res.data.hasOwnProperty('errorMessage')
            ? res.data.errorMessage
            : '数据参数错误'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          self.addProgressFiles(progress)
        }
      })
    },
    // 上传验证
    testUploadLocalFile (files) {
      if (files.length > 50) {
        // 超过50个不能上传
        this.errMessage('一次上传不能超过50个文件')
        return false
      }
      if (files.length === 0) {
        this.errMessage('当前没有选择文件')
        return false
      }
      if (!this.testFilesSize(files)) {
        return false
      }
      return true
    },
    // 验证要发送的文件大小是否符合规则
    testFilesSize (files) {
      console.log(files)
      for (let i = 0; i < files.length; i++) {
        if (files[i].size > 50 * 1024 * 1024) {
          this.errMessage(
            `文件${
              files[i].label ? files[i].label : files[i].name
            }大小超过50M，请重新选择要上传文件`
          )
          return false
        }
      }
      return true
    },
    // 判断文件是否存在
    machineFileExist (path, label) {
      let exist = false
      for (let i = 0; i < this.files.length; i++) {
        if (this.files[i].isFile && this.files[i].label === label) {
          exist = true
          break
        }
      }
      return exist
    },

    // 显示本地选择文件夹弹框
    showLocalDirDialog () {
      let files = this.actFile.filter(item => {
        return item.isFile
      })
      if (files.length === 0) {
        this.noticeMessage('请先选择要下载到本地的文件')
        return
      } else if (files.length > 1) {
        this.noticeMessage('只能选择单个文件下载')
        return
      }
      for (let i = 0; i < files.length; i++) {
        let file = files[i]
        // 添加到传输队列
        this.addProgramArr(
          file,
          '本地路径',
          `machine(${file.position === 'cnc' ? '内部存储' : '外部存储'})`,
          'local',
          '本地路径'
        )
        // 开始下载
        this.startProgram()
      }
    },
    // 下载机器文件到本地的方法
    // 开始发送内部存储文件到外部存储文件
    async putMachineInsideToLocal (program, source) {
      let send = program.sendFile
      let acceptPath =
        program.acceptSource === 'cloud'
          ? program.saveAcceptPath
          : program.acceptPath
      let requestId1 = this.requestId
      let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
      let self = this
      let startTime = new Date()
      let params1 = {
        deviceId: deviceIdItem.id,
        cncPath: send.path,
        boxPath: '',
        requestId: requestId1
      }
      let onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        console.log(data)
        let progress = {
          name: send.label, // 文件名字
          progress: 1, // 传输进度
          state: 'fail', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
          partSize: 16, // 每次上传的大小
          fileSize: send.size, // 文件总大小
          acceptPath, // 接收方地址
          startTime, // 开始时间
          sender: `machine(${
            send.position === 'cnc' ? '内部存储' : '外部存储'
          })`, // 发送方
          acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
          reason:
            data.code === 200 ? boxErr[data.error] : boxCodeErr[data.code], // 传输失败原因
          endTime: self.dateToString(new Date()),
          useTime: '00:00:00'
        }
        try {
          // 这里是放置对其他消息进行处理
          if (
            requestId1 === data.request_id ||
            requestId1 === Number(data.request_id)
          ) {
            if (data.hasOwnProperty('error') && data.error === 0) {
              let sendPath = data.file_path
              this.putMachineToLocal(program, source, sendPath)
            } else {
              // 传输失败，开始传下一个
              this.transfering = false
              this.startProgram()
              self.addProgressFiles(progress)
            }
          }
        } catch (e) {
          console.error(e)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          self.addProgressFiles(progress)
        }
      }
      let newBoxList = await getNewBox([deviceIdItem.id])
      if (!_.isEmpty(newBoxList.data)) {
        const boxRemark = newBoxList.data[0].boxRemark
        if (boxRemark === 0) {
          let ret = await cncToBox(params1)
          if (ret.success) {
            if (ret.data.source === 0) {
              this.onSubscribe(deviceIdItem.id, onMessageArrived)
            }
          } else {
            this.transfering = false
          }
        } else {
          // 直接走下载
          this.putMachineToLocal(program, source, send.path)
        }
      }
    },
    // 从机床下载到本地的方法
    putMachineToLocal (program, source, sendPath = '') {
      console.log(program, 'programprogramprogramprogramprogram')
      let self = this
      let send = program.sendFile
      let deviceIdItem = this.selPathList.find(v => v.type === 'machine')
      let acceptPath =
        program.acceptSource === 'cloud'
          ? program.saveAcceptPath
          : program.acceptPath
      const requestIdNew = this.getRandom()
      let params = {
        deviceId: deviceIdItem.id,
        requestId: requestIdNew,
        fileName: send.label,
        filePath: sendPath.length > 0 ? sendPath : send.path,
        fromBox: send.position === 'box' ? 1 : 0
      }
      if (source === 'machineToCloud') {
        params.cloudPath = program.acceptPath
      }
      // 主要显示传输记录的接收路径
      // 保存到远程
      if (program.acceptName) {
        acceptPath = program.acceptName
      }
      let newUrl
      let startTime = new Date()
      console.log(startTime)
      let fileSize = send.size
      const logParams = {
        fileName: send.label,
        filePath: `${send.position === 'cnc' ? '内部存储' : '外部存储'}${
          send.path
        }`,
        content: '保存至远程',
        fileSize: fileSize,
        onDevice: `${deviceIdItem.name}(${deviceIdItem.assetNumber})`
      }
      let onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        this.isShowInnerLoading = false
        let progress = {
          name: send.label, // 文件名字
          progress: 1, // 传输进度
          state: 'fail', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
          partSize: 16, // 每次上传的大小
          fileSize, // 文件总大小
          acceptPath, // 接收方地址
          startTime, // 开始时间
          sender: `machine(${
            send.position === 'cnc' ? '内部存储' : '外部存储'
          })`, // 发送方
          acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
          reason: '网络繁忙',
          endTime: this.dateToString(new Date()),
          useTime: this.getUseTime(startTime, new Date())
        }
        try {
          // 这里是放置对其他消息进行处理
          if (requestIdNew === Number(data.request_id)) {
            if (
              data.hasOwnProperty('source') &&
              data.source === 'send_result'
            ) {
              if (data.code === 200) {
                let progress = {
                  name: send.label, // 文件名字
                  progress: source === 'machineToLocal' ? 0.9 : 1, // 传输进度
                  state: source === 'machineToLocal' ? 'upload' : 'success', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
                  partSize: 16, // 每次上传的大小
                  fileSize, // 文件总大小
                  acceptPath, // 接收方地址
                  startTime, // 开始时间
                  sender: `machine(${
                    send.position === 'cnc' ? '内部存储' : '外部存储'
                  })`, // 发送方
                  acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
                  endTime: self.dateToString(new Date()),
                  useTime: self.getUseTime(startTime, new Date())
                }
                console.log(progress)
                this.addProgressFiles(progress)
                // console.log(data.url)
                // 判断是传输到本地还是传输到云端，传输到本地还要进行文件下载操作
                if (source === 'machineToLocal') {
                  // 盒子上传到云端已完成，接下来是从云端下载到本地的过程
                  this.putCloudToLocal(send, acceptPath, data.url, startTime)
                } else {
                  this.transfering = false
                  this.startProgram()
                }
              } else {
                this.addProgressFiles(progress)
                // 传输失败，开始传下一个
                this.transfering = false
                this.startProgram()
              }
            }
          }
        } catch (e) {
          console.error(e)
          this.addProgressFiles(progress)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
        }
        this.onUnSubscribeResultBox(requestIdNew)
      }
      let onMessageArrivedNew = res => {
        let data = JSON.parse(res.body).data
        this.isShowInnerLoading = false
        console.log(data)
        this.isShowInnerLoading = false
        try {
          // 这里是放置对其他消息进行处理
          if (requestIdNew === data.cmd_ID) {
            if (data.errorCode === '2000' || data.errorCode === '3000') {
              let progress = {
                name: send.label, // 文件名字
                progress: source === 'machineToLocal' ? 0.9 : 1, // 传输进度
                state: source === 'machineToLocal' ? 'upload' : 'success', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
                partSize: 16, // 每次上传的大小
                fileSize, // 文件总大小
                acceptPath, // 接收方地址
                startTime, // 开始时间
                sender: `machine(${
                  send.position === 'cnc' ? '内部存储' : '外部存储'
                })`, // 发送方
                acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
                endTime: self.dateToString(new Date()),
                useTime: self.getUseTime(startTime, new Date())
              }
              // 保存到本地的情况下
              this.addProgressFiles(progress)
              // 判断是传输到本地还是传输到云端，传输到本地还要进行文件下载操作
              // 盒子上传到云端已完成，接下来是从云端下载到本地的过程
              if (source === 'machineToLocal') {
                // 盒子上传到云端已完成，接下来是从云端下载到本地的过程
                this.putCloudToLocal(send, acceptPath, newUrl, startTime)
              } else {
                this.setLog(logParams)
                this.transfering = false
                this.startProgram()
              }
            } else {
              let progress = {
                name: send.label, // 文件名字
                progress: 1, // 传输进度
                state: 'fail', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
                partSize: 16, // 每次上传的大小
                fileSize, // 文件总大小
                acceptPath, // 接收方地址
                startTime, // 开始时间
                sender: `machine(${
                  send.position === 'cnc' ? '内部存储' : '外部存储'
                })`, // 发送方
                acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
                reason: boxCodeErr[data.errorCode],
                endTime: self.dateToString(new Date()),
                useTime: self.getUseTime(startTime, new Date())
              }
              this.addProgressFiles(progress)
              // 传输失败，开始传下一个
              this.transfering = false
              this.startProgram()
            }
          }
        } catch (e) {
          console.error(e)
          let progress = {
            name: send.label, // 文件名字
            progress: 1, // 传输进度
            state: 'fail', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
            partSize: 16, // 每次上传的大小
            fileSize, // 文件总大小
            acceptPath, // 接收方地址
            startTime, // 开始时间
            sender: `machine(${
              send.position === 'cnc' ? '内部存储' : '外部存储'
            })`, // 发送方
            acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
            reason: '网络繁忙',
            endTime: this.dateToString(new Date()),
            useTime: this.getUseTime(startTime, new Date())
          }
          this.addProgressFiles(progress)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
        }
        this.onUnSubscribeNewBox(requestIdNew)
      }
      this.onSubscribeNewBox(requestIdNew, onMessageArrivedNew)
      this.onSubscribe2(requestIdNew, onMessageArrived) // 结果,
      this.isShowInnerLoading = true
      fileMachineLocal(params).then(res => {
        const ret = res.data
        newUrl = ret.url
      })
      const timerCnc = setTimeout(() => {
        if (this.isShowInnerLoading) {
          this.isShowInnerLoading = false
          this.transfering = false
          this.startProgram()
        } else {
          clearTimeout(timerCnc)
        }
      }, 8000)
      // 上一个进度
      // let lastProgress = null
      // 上传开始时间
    },
    /**
     * 发送云端文件到本地的方法并监听进度
     * @param sendFile 要发送的云端文件文件
     * @param localFilePath 要发送到本地的位置
     * @returns {Promise<void>}
     */
    async putCloudToLocal (
      sendFile,
      localFilePath,
      cloudDownloadPath,
      startTime
    ) {
      let progress = {
        name: sendFile.label, // 文件名字
        progress: 0.66, // 传输进度
        state: 'download', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: sendFile.size, // 每次上传的大小
        fileSize: sendFile.size, // 文件总大小
        acceptPath: localFilePath, // 接收方地址
        startTime, // 开始时间
        sender: `machine(${
          sendFile.position === 'cnc' ? '内部存储' : '外部存储'
        })`, // 发送方
        acceptor: 'local', // 接收方
        endTime: date.formatDate(new Date(), 'MM-DD HH:mm'),
        useTime: this.getUseTime(startTime, new Date())
      }
      let deviceIdItem =
        this.selPathList.find(v => v.type === 'machine') || sendFile.machine
      // 流式下载文件
      const params = {
        cloudPath: cloudDownloadPath
      }
      await getBasisUrl(params)
        .then(info => {
          writeFile(`${info.data}${cloudDownloadPath}`, sendFile, info => {
            let fileRate = info.progress
            progress.size = info.size
            progress.acceptPath = '本地默认路径'
            progress.progress = fileRate
            progress.receiveBytes = info.receiveBytes
            progress.state = info.state
            progress.endTime = date.formatDate(new Date(), 'MM-DD HH:mm')
            progress.useTime = this.getUseTime(startTime, new Date())
            this.addProgressFiles(progress)
            this.setLog({
              fileName: progress.name,
              filePath: `${
                sendFile.position === 'cnc' ? '内部存储' : '外部存储'
              }${sendFile.path}`,
              content: '下载',
              fileSize: sendFile.size,
              onDevice: `${deviceIdItem.name}(${deviceIdItem.assetNumber})`
            })
            if (info.state === 'success') {
              // 传输失败，开始传下一个
              this.transfering = false
              this.startProgram()
            }
          })
        })
        .catch(e => {
          console.log(e)
          // 传输失败，开始传下一个
          progress.state = 'fail'
          progress.endTime = date.formatDate(new Date(), 'MM-DD HH:mm')
          progress.useTime = this.getUseTime(startTime, new Date())
          this.addProgressFiles(progress)
          this.transfering = false
          this.startProgram()
        })
    },

    // 云端到机床
    showCloudFileDialog (event, machinePosition) {
      let position = machinePosition
      if (!machinePosition) {
        let nodeAct = this.selPathList[this.selPathList.length - 1]
        position = nodeAct.position
      }

      this.$refs.cloudFileDialog.showDialog(position)
    },
    /**
     * 云端上传到机床
     * @param cloudFiles 选中的云端文件列表
     * @param machinePosition 发送给内部存储还是外部存储，多设备发送用
     */
    uploadCloudFile (cloudFiles, machinePosition) {
      // 传输前的验证
      if (!this.testUploadLocalFile(cloudFiles)) {
        return
      }
      // 当前所在位置，machineList：机床列表，fileList：文件列表
      let nodeAct = this.selPathList[this.selPathList.length - 1]

      if (this.positionType === 'machine') {
        this.actFile.forEach(machine => {
          cloudFiles.forEach(file => {
            // 添加到传输队列
            this.addMachineProgramArr(machine, file, 'cloud', machinePosition)
          })
        })
      } else if (this.positionType === 'file') {
        cloudFiles.forEach(file => {
          if (this.machineFileExist(nodeAct.path, file.label)) {
            if (nodeAct.position === 'cnc') {
              this.$q.dialog({
                title: `<p class="dialog-notice-title"><i class="iconfont icontubiao-28" ></i> 提示</p>`,
                message: '文件' + file.name + '已存在，内部存储不允许覆盖文件',
                html: true,
                ok: {
                  unelevated: true,
                  label: '确认'
                },
                persistent: true
              })
            } else {
              this.$q
                .dialog({
                  title: `<p class="dialog-notice-title"><i class="iconfont icontubiao-28" ></i> 提示</p>`,
                  message: `文件${file.name}已存在，是否覆盖文件?`,
                  html: true,
                  ok: {
                    unelevated: true,
                    label: '确认'
                  },
                  cancel: {
                    unelevated: true,
                    outline: true,
                    label: '取消'
                  },
                  persistent: true
                })
                .onOk(data => {
                  // 添加到传输队列
                  this.addProgramArr(
                    file,
                    nodeAct.path,
                    'cloud',
                    `machine(${
                      nodeAct.position === 'cnc' ? '内部存储' : '外部存储'
                    })`,
                    nodeAct.path
                  )
                  // 开始下载
                  this.startProgram()
                })
            }
          } else {
            // 添加到传输队列
            this.addProgramArr(
              file,
              nodeAct.path,
              'cloud',
              `machine(${
                nodeAct.position === 'cnc' ? '内部存储' : '外部存储'
              })`,
              nodeAct.path
            )
          }
        })
      }
      // 开始下载
      this.startProgram()
    },
    // 从云端上传到机床的方法
    putCloudToMachine (program) {
      let self = this
      let nodeAct = program.nodeAct
      let position, boxId, storagePath

      if (program.sendStatus === 'single') {
        position = nodeAct.position
        boxId = nodeAct.boxId
        storagePath = nodeAct.path
      } else {
        position = program.machinePosition
        boxId = program.machine.boxStrId
        storagePath = '/'
      }
      // 上一个进度
      let lastProgress = null
      let acceptPath = storagePath + program.sendFile.label // 接收路径
      let fileSize = program.sendFile.size // 文件大小
      let startTime = new Date()
      let progress = {
        name: program.sendFile.label, // 文件名字
        progress: 0, // 传输进度
        state: 'upload', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: 16, // 每次上传的大小
        fileSize, // 文件总大小
        acceptPath, // 接收方地址
        startTime, // 开始时间
        sender: 'cloud', // 发送方
        acceptor: `machine(${position === 'cnc' ? '内部存储' : '外部存储'})`, // 接收方
        endTime: self.dateToString(new Date()),
        useTime: self.getUseTime(startTime, new Date())
      }
      let deviceIdItem =
        this.selPathList.find(v => v.type === 'machine') || program.machine
      const requestIdNew = this.getRandom()
      let params = {
        deviceId: deviceIdItem.id,
        requestId: requestIdNew,
        cloudPath: program.sendFile.path,
        storagePath,
        toCnc: position === 'box' ? 0 : 1
      }
      const logParams = {
        fileName: program.sendFile.label,
        filePath: `${
          position === 'cnc' ? '内部存储' : '外部存储'
        }${acceptPath}`,
        content: '发送',
        fileSize: fileSize,
        onDevice: `${deviceIdItem.name}(${deviceIdItem.assetNumber})`
      }
      let onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        console.log(data)
        try {
          if (requestIdNew === Number(data.request_id)) {
            // 判断是发给内部存储还是外部存储
            // 发给内部存储
            if (position === 'cnc') {
              // 判断result消息
              if (
                data.destinationName ===
                `${
                  this.CommonConfig.socketConfig.SOCKET_TOPIC.machineFileInfo
                    .subscribeTopic
                }${deviceIdItem.id}`
              ) {
                // if (data.hasOwnProperty('error')) {
                if (data.error === 0 && data.code === 200) {
                  // 内部存储发送成功
                  progress.progress = 1
                  progress.state = 'success'
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                  // 上传成功，刷新列表
                  this.refreshFun()
                  // 传输成功，开始传下一个
                  this.transfering = false
                  this.startProgram()
                } else {
                  // 内部存储发送失败
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = data.hasOwnProperty('error')
                    ? boxErr[data.error]
                    : boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                }
              } else if (data.source === 'send_result' && data.code !== 200) {
                // 传输失败，开始传下一个
                this.transfering = false
                this.startProgram()
                progress.progress = 1
                progress.state = 'fail'
                progress.reason = boxCodeErr[data.code]
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                this.addProgressFiles(progress)
              } else if (
                data.source === 'send_info' &&
                (lastProgress === null || lastProgress.progress < data.rate)
              ) {
                // 监听sendInfo发来的进度
                progress.progress = (data.rate / 4) * 3
                progress.state = 'upload'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                this.addProgressFiles(progress)
              }
            } else {
              // 发给外部存储
              if (
                data.source === 'send_result' &&
                data.hasOwnProperty('code')
              ) {
                if (data.code === 200) {
                  // 传输成功，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  progress.progress = 1
                  progress.state = 'success'
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                  // 发送成功，刷新数据
                  this.refreshFun()
                } else {
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                }
              }
            }
          }
        } catch (e) {
          console.error(e)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          progress.progress = data.rate
          progress.state = 'fail'
          progress.reason = '网络繁忙'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          this.addProgressFiles(progress)
        }
        this.onUnSubscribeResultBox(requestIdNew)
      }
      let onMessageArrivedNew = res => {
        let data = JSON.parse(res.body).data
        console.log(data)
        try {
          if (requestIdNew === data.cmd_ID) {
            // 判断是发给内部存储还是外部存储
            // 发给内部存储
            if (position === 'cnc') {
              // 判断result消息
              if (data.errorCode === '3000') {
                // 内部存储发送成功
                progress.state = 'success'
                this.setLog(logParams)
              } else {
                // 内部存储发送失败
                progress.state = 'fail'
                progress.reason = boxCodeErr[data.errorCode]
              }
              progress.progress = 1
              progress.endTime = self.dateToString(new Date())
              progress.useTime = self.getUseTime(startTime, new Date())
              this.transfering = false
              this.startProgram()
              this.addProgressFiles(progress)
              this.refreshFun()
            } else {
              // 发给外部存储
              if (data.errorCode === '2000') {
                this.setLog(logParams)
                // 传输成功，开始传下一个
                this.transfering = false
                this.startProgram()
                progress.progress = 1
                progress.state = 'success'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                this.addProgressFiles(progress)
                // 发送成功，刷新数据
                this.refreshFun()
              } else {
                // 传输失败，开始传下一个
                this.transfering = false
                this.startProgram()
                progress.progress = 1
                progress.state = 'fail'
                progress.reason = boxCodeErr[data.errorCode]
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                this.addProgressFiles(progress)
              }
            }
          }
        } catch (e) {
          console.error(e)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          progress.progress = data.rate
          progress.state = 'fail'
          progress.reason = '网络繁忙'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          this.addProgressFiles(progress)
        }
        this.onUnSubscribeNewBox(requestIdNew)
      }
      this.onSubscribeNewBox(requestIdNew, onMessageArrivedNew)
      this.onSubscribe2(requestIdNew, onMessageArrived)
      if (position === 'cnc') {
        this.onSubscribe(deviceIdItem.id, onMessageArrived)
      }
      // 发送到多台的数据标识
      if (program.sendStatus === 'many') {
        progress.boxId = boxId
      }
      fileMachineCloud(params).then(res => {
        if (res.data.hasOwnProperty('requestId')) {
        } else {
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          progress.progress = 1
          progress.state = 'fail'
          progress.reason = res.data.hasOwnProperty('errorMessage')
            ? res.data.errorMessage
            : '数据参数错误'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          this.addProgressFiles(progress)
        }
      })
    },
    // type success 1 fail 0
    // progerss startTime
    isStartProgress (type, progress, startTime) {
      this.transfering = false
      this.startProgram()
      progress.progress = 1
      progress.state = 'fail'
      progress.reason = '网络繁忙'
      progress.endTime = self.dateToString(new Date())
      progress.useTime = self.getUseTime(startTime, new Date())
      this.addProgressFiles(progress)
    },
    // 机床到云端
    showCloudSelDir () {
      let files = this.actFile.filter(item => {
        return item.isFile
      })
      if (files.length === 0) {
        this.noticeMessage('请先选择要保存到远程的文件')
        return
      }
      this.$refs.cloudSelDir.showDialog()
    },
    /**
     * 通过弹框获取的云端要传输的所在位置
     * @param cloudDir 云端文件夹目录
     */
    uploadMachineToCloud (cloudDir) {
      let files = this.actFile.filter(item => {
        return item.isFile
      })
      if (!this.testUploadLocalFile(files)) return
      files.forEach(item => {
        // 判断文件是否存在
        let savePath = cloudDir.path + item.label
        cloudFileExist(savePath).then(res => {
          if (res.data) {
            this.$q
              .dialog({
                title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
                message: '文件' + item.label + '已存在，是否覆盖文件',
                html: true,
                ok: {
                  unelevated: true,
                  label: '确认'
                },
                cancel: {
                  unelevated: true,
                  outline: true,
                  label: '取消'
                },
                persistent: true
              })
              .onOk(data => {
                this.addProgramArr(
                  item,
                  cloudDir.path,
                  `machine(${
                    item.position === 'cnc' ? '内部存储' : '外部存储'
                  })`,
                  'cloud',
                  cloudDir.path,
                  cloudDir.name
                )
                this.startProgram()
              })
          } else {
            this.addProgramArr(
              item,
              cloudDir.path,
              `machine(${item.position === 'cnc' ? '内部存储' : '外部存储'})`,
              'cloud',
              cloudDir.path,
              cloudDir.name
            )
            this.startProgram()
          }
        })
      })
    },

    // 添加到传输列表。发送时，处于文件列表页
    addProgramArr (
      sendFile,
      acceptPath,
      sendSource,
      acceptSource,
      saveAcceptPath,
      acceptName
    ) {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      this.programArr.push({
        sendFile,
        acceptPath,
        sendSource,
        acceptSource,
        nodeAct,
        saveAcceptPath,
        acceptName,
        sendStatus: 'single' // 发送时，处于文件列表页
      })
      let startTime = new Date()
      if (acceptName) {
        acceptPath = acceptName
        saveAcceptPath = acceptName
      }
      let progress = {
        name: sendSource === 'local' ? sendFile.name : sendFile.label, // 文件名字
        progress: 0, // 传输进度
        state: 'upload', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: 16, // 每次上传的大小
        fileSize: 0, // 文件总大小
        acceptPath: acceptSource === 'cloud' ? acceptPath : saveAcceptPath, // 接收方地址
        startTime, // 开始时间
        sender: sendSource, // 发送方
        acceptor: acceptSource, // 接收方
        endTime: this.dateToString(new Date()),
        useTime: this.getUseTime(startTime, new Date())
      }
      this.addProgressFiles(progress)
    },
    // 传输一个文件
    startProgram () {
      // 如果此时已在传输中，这次请求就打回
      if (this.transfering) {
        return
      }
      if (this.programArr.length > 0) {
        let program = this.programArr.shift()
        this.transfering = true
        setTimeout(() => {
          // 在文件页面发送
          if (program.sendStatus === 'single') {
            if (
              program.sendSource === 'local' &&
              program.acceptSource.indexOf('machine') > -1
            ) {
              // 本地到机床
              // 外部 - 文件 - 本地发送
              this.putLocalToMachine(program)
            } else if (
              program.acceptSource === 'local' &&
              program.sendSource.indexOf('machine') > -1
            ) {
              // 机床到本地
              if (program.sendFile.position === 'cnc') {
                // 内部 - 文件 - 下载到本地
                this.putMachineInsideToLocal(program, 'machineToLocal')
              } else {
                // 外部存储 - 文件 - 下载到本地
                this.putMachineToLocal(program, 'machineToLocal')
              }
            } else if (
              program.sendSource === 'cloud' &&
              program.acceptSource.indexOf('machine') > -1
            ) {
              // 云端到机床
              // 外部 - 文件 - 远程发送
              this.putCloudToMachine(program)
            } else if (
              program.acceptSource === 'cloud' &&
              program.sendSource.indexOf('machine') > -1
            ) {
              // 机床到云端
              if (program.sendFile.position === 'cnc') {
                // 内部 =  文件 - 保存到远程
                this.putMachineInsideToLocal(program, 'machineToCloud')
              } else {
                // 外部存储 - 文件 - 保存到云端
                this.putMachineToLocal(program, 'machineToCloud')
              }
            }
          } else {
            // 在设备页面发送
            if (program.sendSource === 'local') {
              this.putLocalToMachine(program)
            } else if (program.sendSource === 'cloud') {
              this.putCloudToMachine(program)
            }
          }
        }, 300)
      }
    },
    // 根据开始时间和结束时间，获取累计用时时间，返回hh:mm:ss
    getUseTime (startTime, endTime) {
      let useTime = (endTime.getTime() - startTime.getTime()) / 1000
      let seconds = parseInt(useTime % 60)
      seconds = seconds < 10 ? '0' + seconds : seconds
      let minutes = parseInt((useTime / 60) % 60)
      minutes = minutes < 10 ? '0' + minutes : minutes
      let hours = parseInt((useTime / 3600) % 60)
      hours = hours < 10 ? '0' + hours : hours
      return `${hours}:${minutes}:${seconds}`
    },
    // 根据Date格式的日期,返回 mm-dd hh:mm
    dateToString (date) {
      let months = date.getMonth() + 1
      months = months < 10 ? '0' + months : months
      let dates = date.getDate()
      dates = dates < 10 ? '0' + dates : dates
      let hours = date.getHours()
      hours = hours < 10 ? '0' + hours : hours
      let minutes = date.getMinutes()
      minutes = minutes < 10 ? '0' + minutes : minutes
      return `${months}-${dates} ${hours}:${minutes}`
    },

    // 传输过程中相关
    // 添加上传中和上传完成的文件
    addProgressFiles (file) {
      // 添加传输目录
      const index = this.progressFiles.findIndex(item => {
        if (file.hasOwnProperty('boxId') || file.hasOwnProperty('deviceId')) {
          return (
            item.name === file.name &&
            item.acceptor === file.acceptor &&
            item.boxId === file.boxId
          )
        } else {
          return item.name === file.name && item.acceptor === file.acceptor
        }
      })

      // 开始传输
      if (index === -1) {
        this.$refs.progressDialog.showDialog()
        this.progressFiles.unshift(file)
      } else {
        this.progressFiles[index].progress = file.progress
        this.progressFiles[index].useTime = file.useTime
        this.progressFiles[index].state = file.state
        this.progressFiles[index].fileSize = file.fileSize
      }
      // 传输失败
      if (file.state === 'fail') {
        this.failProgressFiles.unshift(file)
        saveProgressFailRecord(this.userInfo.tenant_id, this.failProgressFiles)
      } else if (file.state === 'success') {
        // 传输成功
        this.successProgressFiles.unshift(file)
        saveProgressSuccessRecord(
          this.userInfo.tenant_id,
          this.successProgressFiles
        )
      }
      this.doingProgressFiles = this.progressFiles.filter(item => {
        return item.state !== 'fail' && item.state !== 'success'
      })
      this.isOverProgress()
    },
    // 判断所有文件是否上传完成，完成择1.5s后消失
    isOverProgress () {
      if (this.doingProgressFiles.length === 0) {
        this.progressTime = setTimeout(() => {
          this.$refs.progressDialog.hideDialog()
          this.progressFiles = []
        }, 1500)
      } else {
        clearTimeout(this.progressTime)
      }
    },
    // 传输记录相关
    // 显示传输记录弹框
    showProgressResult () {
      this.$refs.progressResult.showDialog()
    },
    // 删除一条传输记录
    delOneRecord (state, file) {
      if (state === 'success') {
        this.successProgressFiles = this.successProgressFiles.filter(item => {
          return !(
            item.name === file.name && item.startTime === file.startTime
          )
        })
        saveProgressSuccessRecord(
          this.userInfo.tenant_id,
          this.successProgressFiles
        )
      }
      if (state === 'fail') {
        this.failProgressFiles = this.failProgressFiles.filter(item => {
          return item.name !== file.name && item.startTime !== file.startTime
        })
        saveProgressFailRecord(this.userInfo.tenant_id, this.failProgressFiles)
      }
    },
    // 清空传输记录
    clearRecord (state) {
      if (state === 'success') {
        this.successProgressFiles = []
        clearProgressSuccessRecord(
          this.userInfo.tenant_id,
          this.successProgressFiles
        )
      }
      if (state === 'fail') {
        this.failProgressFiles = []
        clearProgressFailRecord(
          this.userInfo.tenant_id,
          this.failProgressFiles
        )
      }
    },
    // 传输记录按照时间排序
    sortRecord (record) {
      let newRecord = record.sort((a, b) => {
        if (a.endTime < b.endTime) {
          return 1
        } else if (a.endTime > b.endTime) {
          return -1
        } else return 0
      })
      newRecord = newRecord.map(item => {
        return {
          ...item,
          acceptPath: item.acceptPath
            ? item.acceptPath.replace('//', '/')
            : item.acceptPath
        }
      })
      return newRecord
    },

    // 框选
    // 鼠标按下事件
    boxStart (event, parentDom) {
      if (
        event.target.tagName === 'IMG' ||
        event.target.tagName === 'SPAN' ||
        event.target.className.indexOf('txt-ellipsis') > -1
      ) {
        return true
      }
      // 判断鼠标是否是左键按下
      if (event.buttons !== 1 || event.which !== 1) return
      let parentNode = this.$refs[parentDom]
      this.parentX = getOffsetLeft(parentNode)
      this.parentY = getOffsetTop(parentNode)
      this.parentW = parentNode.clientWidth
      this.parentH = parentNode.clientHeight
      let self = this
      clearTimeout(this.mouseTime)
      let startTime = new Date()

      this.mouseOn = true
      this.startX = event.clientX - this.parentX
      this.startY = event.clientY - this.parentY
      let boxSelect = this.$refs.boxSelect
      boxSelect.style.display = 'block'
      boxSelect.style.left = this.startX + 'px'
      boxSelect.style.top = this.startY + 'px'
      boxSelect.style.zIndex = -1
      boxSelect.style.width = 0
      boxSelect.style.height = 0
      document.onmousemove = function (event) {
        self.boxMove(event, parentDom)
      }
      this.$refs[parentDom].onmouseup = function (event) {
        // self.$refs[parentDom].onmousemove = null
        document.onmousemove = null
        clearTimeout(this.mouseTime)
        let endTime = new Date()
        if (endTime.getTime() - startTime.getTime() < 200) {
          self.isClickEvent = true
        }
        self.boxStop(event)
      }
    },
    // 鼠标移动事件
    boxMove (event, parentDom) {
      // 如果框选没有开启。退出
      if (!this.mouseOn) return

      let clientX = event.clientX
      let clientY = event.clientY
      let _x = clientX - this.parentX
      let _y = clientY - this.parentY
      let boxSelect = this.$refs.boxSelect

      boxSelect.style.left = Math.min(_x, this.startX) + 'px'
      boxSelect.style.top = Math.min(_y, this.startY) + 'px'
      boxSelect.style.width = Math.abs(_x - this.startX) + 'px'
      boxSelect.style.height = Math.abs(_y - this.startY) + 'px'
      boxSelect.style.zIndex = 100
      this.findNodes(event)
      // 当框选超出范围时，结束框选操作,取消move和mouseup监听
      if (
        clientX < this.parentX ||
        clientX > this.parentX + this.parentW ||
        clientY < this.parentY ||
        clientY > this.parentY + this.parentH
      ) {
        document.onmousemove = null
        this.$refs[parentDom].onmouseup = null
        clearTimeout(this.mouseTime)

        this.boxStop(event)
      }
    },
    // 鼠标松开事件
    boxStop (event) {
      this.mouseOn = false
      this.findNodes(event)
      let boxSelect = this.$refs.boxSelect
      boxSelect.style.display = 'none'
      boxSelect.style.width = 0
      boxSelect.style.height = 0
    },
    // 获取框选下的元素
    findNodes (event) {
      let dayNodes = document.getElementsByClassName('file-item')
      let boxSelect = this.$refs.boxSelect
      let selectedEls = []
      // 获取框的参数
      let l = boxSelect.offsetLeft
      let t = boxSelect.offsetTop
      let w = boxSelect.offsetWidth
      let h = boxSelect.offsetHeight

      for (let i = 0; i < dayNodes.length; i++) {
        let dayNode = dayNodes[i]
        let sl = dayNode.offsetWidth + dayNode.offsetLeft
        let st = dayNode.offsetHeight + dayNode.offsetTop
        if (
          sl > l &&
          st > t &&
          dayNode.offsetLeft < l + w &&
          dayNode.offsetTop < t + h
        ) {
          selectedEls.push(this.files[i])
        }
      }
      if (event.ctrlKey || event.shiftKey) {
        this.actFile = this.actFile.concat(selectedEls)
      } else {
        this.actFile = selectedEls
      }
    },
    // 提示
    // 成功提示
    successMessage (message) {
      this.$message.success(message)
    },
    // 失败提示
    errMessage (message) {
      this.$message.error(message)
    },
    // 注意提示
    noticeMessage (message) {
      this.$message.warning(message)
    },
    // 获取随机数 默认1-2147483647
    getRandom (min = 1, max = 2147483647) {
      min = Math.ceil(min)
      max = Math.floor(max)
      return Math.floor(Math.random() * (max - min + 1)) + min
    },
    // 操作日志
    setLog ({ fileName, filePath, content, fileSize, onDevice }) {
      postFileLog({
        fileName,
        filePath,
        content,
        fileSize,
        onDevice
      })
    }
  },
  components: {
    TreeList,
    Unfold,
    SelectInput,
    Position,
    ProgressDialog,
    ProgressResultDialog,
    FileItem,
    FileItemTr,
    CodeEdit,
    CloudFileDialog,
    CloudSelDir,
    Drawer
  }
}
</script>

<style scoped lang="stylus">
.program-transfer{
  .file-head{
    padding 0 20px
    height 40px
    line-height 40px
    font-size 14px
    align-items center
    flex 40px 0
    .icon{
      margin-left 10px
      font-size 18px
    }
    /deep/ .q-btn-group > .q-btn-item:not(:last-child) {
      min-width 78px
      padding 0px
    }
    /deep/ .q-btn-group > .q-btn-item + .q-btn-item {
      min-width 14px
      width 18px
      padding 0
    }
    .btn-dropdown{
      min-width 100px
    }
  }
  .list-content{
    height calc(100% - 121px)
  }
  .list{
    padding 10px
    display flex
    flex-wrap wrap
  }
  .table-file {
    height 100%
  }
  .machine-file{
    width 156px
    height 140px
    /deep/ dt{
      margin-bottom 16px
      .q-icon{
        font-size 72px
      }
    }
  }
  .file-bottom{
    text-align right
    padding 0 20px
    height 39px
    line-height 39px
    border-top 1px solid #d3d3d3
    .text-underline{
      text-decoration underline
    }
  }
  // 框选样式
  .box-select{
    position absolute
    margin 0
    padding 0
    top 0
    left 0
    width 10px
    height 10px
    border 1px dashed $primary
    background-color $primary
    z-index 1000
    opacity 0.6
    display none
  }
}
</style>
